﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Net;
using System.IO;

namespace GMusicBox.Core
{
    public sealed class Song
    {
        public Song()
        {
            Album = new Album();
            Artist = new Artists();
            CanBeDownloaded = false;
            Duration = 0;
            Id = "";
            Name = "";
            RingtoneUrl = "";
        }

        public Album Album { get; internal set; }

        public Artists Artist { get; internal set; }

        public bool CanBeDownloaded { get; internal set; }

        public double Duration { get; internal set; }

        public bool HasFullLyrics { get; internal set; }

        public string Id { get; internal set; }

        public string Name { get; internal set; }

        public string RingtoneUrl { get; internal set; }

        public static Song Create(string id)
        {
            return Create(id, "", null, null, 0, true, true, "");
        }

        public static Song Create(string id, string name, Artists artist, Album album, double duration, bool canBeDownloaded, bool hasFullLyrics, string ringtoneUrl)
        {
            Song s = new Song();
            s.Id = id;
            s.Name = name;
            s.Artist = artist;
            s.Album = album;
            s.Duration = duration;
            s.CanBeDownloaded = canBeDownloaded;
            s.HasFullLyrics = hasFullLyrics;
            s.RingtoneUrl = ringtoneUrl == null ? "" : ringtoneUrl;
            return s;
        }

        public string GetDownloadUrl()
        {
            if (Id == "") throw new ArgumentNullException("歌曲Id未指定，无法执行 GetDownloadUrl 函数。");

            try
            {
                string html = "";
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.cn/music/top100/musicdownload?id=" + Id);
                request.Accept = "*/*";
                HttpWebResponse response = null;
                Stream stream = null;
                StreamReader reader = null;
                try
                {
                    response = (HttpWebResponse)request.GetResponse();
                    stream = response.GetResponseStream();
                    reader = new StreamReader(stream, Encoding.Default);
                    html = reader.ReadToEnd();
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                        reader.Dispose();
                    }
                    if (stream != null)
                    {
                        stream.Close();
                        stream.Dispose();
                    }
                    if (response != null)
                    {
                        response.Close();
                    }
                }

                int front = html.IndexOf("<a href=\"/music/top100/url?q=http://", StringComparison.CurrentCultureIgnoreCase) + 9;
                int last = html.IndexOf("\"><img src=\"", front);
                string Url = "http://www.google.cn" + html.Substring(front, last - front);
                Url = Url.Replace("%3A", ":").Replace("%2F", "/").Replace("&amp;", "&");
                return Url;
            }
            catch { }
            return null;
        }

        public static string GetSearchURL(string keyWord)
        {
            return GetSearchURL(keyWord, 800);
        }

        public static string GetSearchURL(string keyWord, int searchCount)
        {
            if (searchCount <= 0) throw new ArgumentException("搜索总数必须大于 0 且小于等于 800。", "searchCount");
            return "http://www.google.cn/music/search?q=" + keyWord + "&num=" + searchCount.ToString() + "&output=xml";
        }

        public static string GetSongListName(string url)
        {
            XmlDocument xd = new XmlDocument(); xd.Load(url);
            XmlNode xn = xd.SelectSingleNode("results/listname");
            return xn.InnerText;
        }
        
        public static Song[] GetSongList(string url)
        {
            return GetSongList(url, "results/songList/song");
        }

        public static Song[] GetSongList(string url, string xpath)
        {
            XmlDocument xd = new XmlDocument(); xd.Load(url);
            return GetSongList(xd, xpath);
        }

        internal static Song[] GetSongList(XmlDocument xd, string xpath)
        {
            XmlNodeList xn = xd.SelectNodes(xpath);
            List<Song> song = new List<Song>();
            foreach (XmlNode x in xn)
            {
                Song s = new Song();
                s.Album = new Album(x.SelectSingleNode("albumId").InnerText, x.SelectSingleNode("album").InnerText);
                s.CanBeDownloaded = Convert.ToBoolean(x.SelectSingleNode("canBeDownloaded").InnerText);
                s.Duration = double.Parse(x.SelectSingleNode("duration").InnerText);
                if (x.SelectSingleNode("hasFullLyrics") != null &&
                    x.SelectSingleNode("hasFullLyrics").InnerText != "") s.HasFullLyrics = Convert.ToBoolean(x.SelectSingleNode("hasFullLyrics").InnerText);
                s.Id = x.SelectSingleNode("id").InnerText;
                s.Name = x.SelectSingleNode("name").InnerText;
                if (x.SelectSingleNode("ringtoneUrl") != null) s.RingtoneUrl = x.SelectSingleNode("ringtoneUrl").InnerText;

                XmlNodeList artist = x.SelectNodes("artist");
                XmlNodeList artistId = x.SelectNodes("artistId");
                List<Artist> artists = new List<Artist>();
                for (int i = 0; i < artist.Count; i++)
                    if (artist[i].InnerText != null && artist[i].InnerText != "")
                        artists.Add(new Artist(artistId[i].InnerText, artist[i].InnerText));
                s.Artist.Items.AddRange(artists);

                song.Add(s);
            }
            return song.ToArray();
        }

        public static Song[] Search(string keyWord, int page, out int resultCount)
        {
            try
            {
                XmlDocument xd = new XmlDocument();
                xd.Load("http://www.google.cn/music/search?q=" + keyWord + "&start=" + (page * 20).ToString() + "&output=xml");
                //xd.Load("C:\\Users\\hjkcai\\Desktop\\Search.xml");
                XmlNode xn = xd.SelectSingleNode("results").SelectSingleNode("estimatedResultCount");
                if (xn == null) resultCount = 800;
                else resultCount = int.Parse(xn.InnerText);
                return GetSongList(xd, "results/songList/song");
            }
            catch { }
            resultCount = 0;
            return null;
        }

        public override string ToString()
        {
            return Artist.ToString() + " - " + Name;
        }

        internal string ToXML(int Indent)
        {
            string indent = "";
            string body = "";
            for (int i = 0; i < Indent; i++) indent += "\t";
            body += indent + "<song>\r\n"; indent += "\t";
            body += string.Format("{0}<id>{1}</id>\r\n", indent, Helper.ReplaceXMLchars(Id));
            body += string.Format("{0}<name>{1}</name>\r\n", indent, Helper.ReplaceXMLchars(Name));
            foreach (Artist a in Artist.Items)
            {
                body += string.Format("{0}<artist>{1}</artist>\r\n", indent, Helper.ReplaceXMLchars(a.Name));
                body += string.Format("{0}<artistId>{1}</artistId>\r\n", indent, Helper.ReplaceXMLchars(a.Id));
            }
            body += string.Format("{0}<album>{1}</album>\r\n", indent, Helper.ReplaceXMLchars(Album.Name));
            body += string.Format("{0}<albumId>{1}</albumId>\r\n", indent, Helper.ReplaceXMLchars(Album.Id));
            body += string.Format("{0}<duration>{1}</duration>\r\n", indent, Duration);
            body += string.Format("{0}<canBeDownloaded>{1}</canBeDownloaded>\r\n", indent, CanBeDownloaded);
            body += string.Format("{0}<hasFullLyrics>{1}</hasFullLyrics>\r\n", indent, HasFullLyrics);
            body += string.Format("{0}<ringtoneUrl>{1}</ringtoneUrl>\r\n", indent, Helper.ReplaceXMLchars(RingtoneUrl));
            body += indent.Substring(0, indent.Length - 1) + "</song>\r\n";
            return body;
        }
    }
}
